package info.openrocket.swing.logging;




/**
 * An exception that is used to store a stack trace.  On modern computers
 * instantiation of an exception takes on the order of one microsecond, while
 * examining the trace typically takes several times longer.  Therefore the
 * exception should be stored and the stack trace examined only when necessary.
 * <p>
 * The {@link #getLocation()} method returns a description of the position
 * where this exception has been instantiated.
 * 
 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
 */
class TraceException {
	
	private static final String STANDARD_PACKAGE_PREFIX = "info.openrocket.swing.";
	private static final String EXCLUDED_PACKAGE_PREFIX = "info.openrocket.swing.logging";
	
	private final Throwable t;
	private volatile String location;
	
	TraceException() {
		t = new Throwable();
	}
	
	public String getLocation() {
		if (location == null) {
			StackTraceElement[] elements = t.getStackTrace();
			
			StringBuilder sb = new StringBuilder();
			sb.append('(');
			
			if (elements == null || elements.length == 0) {
				sb.append("no stack trace");
			} else {
				
				int found = -1;
				int index = 0;
				while (found < 0 && index < elements.length) {
					
					// Ignore synthetic "access$0" methods generated by the JRE
					if (elements[index].getMethodName().contains("$")) {
						index++;
						continue;
					}
					
					String className = elements[index].getClassName();
					if (!className.startsWith(EXCLUDED_PACKAGE_PREFIX) && className.startsWith(STANDARD_PACKAGE_PREFIX)) {
						sb.append(toString(elements[index]));
						found = 1;
						break;
					}
					
					index++;
					
				}
				if (found < 0) {
					sb.append(toString(elements[0]));
				}
			}
			sb.append(')');
			
			location = sb.toString();
		}
		return location;
	}
	
	
	private static String toString(StackTraceElement element) {
		if (element.getClassName().startsWith(STANDARD_PACKAGE_PREFIX)) {
			return element.getFileName() + ":" + element.getLineNumber();
		} else {
			return element.toString();
		}
	}
	
}
